#include "client.h"
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/filesystem.hpp>
#include <boost/thread/thread.hpp>

void cget::Client::connect() {
	string host = conf.getConfig(c_host);
	string port = conf.getConfig(c_port);
	string protocol = conf.getConfig(c_protocol);
	unsigned int tries;
	unsigned int waitretry;

	try {
		tries = boost::lexical_cast<unsigned int>(conf.getConfig(c_tries));
	} catch(boost::bad_lexical_cast& e) {
		throw string("configure error : tries");
	}

	try {
		waitretry = boost::lexical_cast<unsigned int>(conf.getConfig(c_waitretry));
	} catch(boost::bad_lexical_cast& ) {
		throw string("configure error : waitretry");
	}

	//cout << "tries = " << tries << endl;
	//cout << "waitretry = " << waitretry << endl;
	
	cout << host << "\t" << protocol << endl;
	for(unsigned int i = 0; i < tries; ++i) {
		cout << "tries : " << i << endl;

		tcp::resolver reso(ios);
		tcp::resolver::query query(host,protocol);
		tcp::resolver::iterator endpoint_iterator;
		tcp::resolver::iterator end;
		
		try {
			endpoint_iterator = reso.resolve(query);
		} catch(...) {
			cout << "resolve failed : " << host << " " << protocol << endl;
		}

		boost::system::error_code error = boost::asio::error::host_not_found;
		while(error && endpoint_iterator != end) {
			sock.close();
			sock.connect(*endpoint_iterator++,error);
		}
		
		if(error) {
			cout << error.message() << endl;
			if(i == (tries-1))
				throw string("all tried,but failed");
		}
		else {
			cout << "connect succeeded" << endl;
			break;
		}

		cout << "connect failed,sleep for " << waitretry << " seconds" << endl;
		boost::xtime xt;
		boost::xtime_get(&xt,boost::TIME_UTC);
		xt.sec += waitretry;
		boost::thread::sleep(xt);

	}
}

void cget::Client::run() { 

	connect();
	size_t filesize = getFileSize();

	ostringstream ostream;
	ostream << filesize;
	conf.setConfig(c_filesize,ostream.str());
	
	string cont_file = conf.getConfig(c_filename) + ".c-get";

	if(!boost::filesystem::exists(cont_file)) {
		con_ptr = continue_ptr(new Continue(conf));
		con_ptr->sync();
		ofstream ofs(conf.getConfig(c_filename).c_str(),ios::binary|ios::trunc);
		ofs.close();
	}
	else {
		con_ptr = continue_ptr(new Continue(cont_file));
	}
	
	int num_threads;
	int num_block = con_ptr->getNumBlock();
	int step;

	try {
		num_threads = boost::lexical_cast<int>(conf.getConfig(c_threads));
	} catch(boost::bad_lexical_cast& e) {
		throw string("number of threads error");
	}
	if(num_threads > num_block)
		num_threads = num_block;

	step = num_block / num_threads;
	cout << "threads " << num_threads << endl;
	cout << "num_block " << num_block << endl;
	cout << "step " << step << endl;
	
	boost::thread_group thread_group;
	for(int i = 0; i < num_threads; ++i) {
		int from = step*i;
		int to = step*(i+1)-1;
		if(i == (num_threads-1))
			to = num_block-1;
		thread_group.create_thread(boost::bind(&Client::thread_func,this,from,to));
	}

	thread_group.join_all();
}

cget::client_ptr cget::Client::getClient(Config& c) {
	string protocol = c.getConfig(cget::c_protocol);

	if(protocol == "http")
		return cget::client_ptr(new cget::HttpClient(c));

	throw string("protocol not supported:" + protocol);
	//return cget::client_ptr(new cget::Client());
}


size_t cget::HttpClient::getFileSize() {

	return 10000000;
}

void cget::HttpClient::thread_func(int from,int to) {

	cout << "from = " << from << "\t" << "to = " << to << endl;

}
